package org.linlinjava.litemall.admin.controller;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.validation.constraints.NotNull;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.linlinjava.litemall.admin.beans.Constants;
import org.linlinjava.litemall.admin.beans.annotation.LogAnno;
import org.linlinjava.litemall.admin.beans.annotation.LoginAdminId;
import org.linlinjava.litemall.admin.beans.dto.CouponQueryDto;
import org.linlinjava.litemall.admin.beans.dto.GrantExtenDto;
import org.linlinjava.litemall.admin.beans.vo.CouponStatisticVo;
import org.linlinjava.litemall.admin.beans.vo.CouponUserVo;
//import org.linlinjava.litemall.admin.beans.vo.CouponVo;
import org.linlinjava.litemall.admin.util.PageUtil;
import org.linlinjava.litemall.admin.vo.AdminCouponReadVO;
import org.linlinjava.litemall.core.notify.AwsNotifyService;
import org.linlinjava.litemall.core.notify.NoticeHelper;
import org.linlinjava.litemall.core.notify.NotifyService;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.core.validator.Order;
import org.linlinjava.litemall.core.validator.Sort;
import org.linlinjava.litemall.db.dao.LitemallCouponMapper;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.dto.LitemallOrderDto;
import org.linlinjava.litemall.db.service.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import static org.linlinjava.litemall.admin.util.AdminResponseCode.MOBILE_CODE_ONE;

/**
 * 管理优惠券控制器
 *
 * @author yliyun
 * @date 2022/09/14
 */
@RestController
@RequestMapping("/admin/coupon")
@Validated
public class AdminCouponController {

    /**
     * 息服务
     */
    @Autowired
    private LitemallCouponService couponService;

    @Autowired
    private LitemallCouponMapper couponMapper;
    /**
     * 优惠券用户服务
     */
    @Autowired
    private LitemallCouponUserService couponUserService;
    /**
     * 商品服务
     */
    @Autowired
    private LitemallGoodsService goodsService;
    /**
     * 订单服务
     */
    @Autowired
    private LitemallOrderService orderService;
    /**
     * 目录服务
     */
    @Autowired
    private LitemallCategoryService categoryService;

    /**
     * litemall优惠券用户服务
     */
    @Autowired
    private LitemallCouponUserService litemallCouponUserService;

    /**
     * litemall店地区服务
     */
    @Autowired
    private LitemallShopRegionService litemallShopRegionService;

    /**
     * litemall用户服务
     */
    @Autowired
    private LitemallUserService litemallUserService;

    /**
     * 通知服务
     */
    @Autowired
    private NotifyService notifyService;

    /**
     * litemall订单服务
     */
    @Autowired
    private LitemallOrderService litemallOrderService;

    /**
     * 店服务
     */
    @Autowired
    private LitemallShopService shopService;

    /**
     * 订单商品服务
     */
    @Autowired
    private LitemallOrderGoodsService orderGoodsService;

    /**
     * 卢米埃支付会员用户服务
     */
    @Autowired
    private LumierePayMemberUserService lumierePayMemberUserService;

    /**
     * aws通知服务
     */
    @Autowired
    private AwsNotifyService awsNotifyService;

    /**
     * 地区服务
     */
    @Autowired
    private LitemallRegionService regionService;

    /**
     * 注意助手
     */
    @Autowired
    private NoticeHelper noticeHelper;


    /**
     * 列表
     *
     * @param name         名字
     * @param type         类型
     * @param status       状态
     * @param ranges       范围
     * @param lossBearing  承担损失
     * @param areaLimit    区域限制
     * @param discountType 折扣类型
     * @param isExpired    是过期
     * @param page         页面
     * @param limit        限制
     * @param sort         排序
     * @param order        订单
     * @return {@link Object}
     */
    @GetMapping("/list")
    @LogAnno
    public Object list(String name, Short type, Short status, Short ranges,
                       Short lossBearing, Short areaLimit, Byte discountType, Boolean isExpired,
                       @RequestParam(defaultValue = "1") Integer page,
                       @RequestParam(defaultValue = "10") Integer limit,
                       @Sort @RequestParam(defaultValue = "add_time") String sort,
                       @Order @RequestParam(defaultValue = "desc") String order) {
        List<LitemallCoupon> couponList = couponService.querySelective(name, type, lossBearing, status, areaLimit, discountType, page, limit, sort, order, ranges, isExpired);
        return ResponseUtil.okList(couponList);
    }

    /**
     * 在成员列表
     *
     * @param isExpired 是过期
     * @param page      页面
     * @param limit     限制
     * @param sort      排序
     * @param order     订单
     * @return {@link Object}
     */
    @GetMapping("/listInMember")
    @LogAnno
    public Object listInMember(Boolean isExpired,
                               @RequestParam(defaultValue = "1") Integer page,
                               @RequestParam(defaultValue = "10") Integer limit,
                               @Sort @RequestParam(defaultValue = "add_time") String sort,
                               @Order @RequestParam(defaultValue = "desc") String order) {

        List<LitemallCoupon> couponList = couponService.querySelectiveInMember(page, limit, sort, order, isExpired);
        return ResponseUtil.okList(couponList);
    }

    /**
     * exten优惠券列表
     *
     * @return {@link Object}
     */
    @GetMapping("/extenCouponList")
    @LogAnno
    public Object extenCouponList() {
        List<LitemallCoupon> couponList = couponService.querySelective(null, (short) 3, null, (short) 1, null, null, null, null, null, null, null, false);

        couponList = couponList.stream().filter(coupon -> {
            Integer count = litemallCouponUserService.countCoupon(coupon.getId());
            if (count < coupon.getTotal()) {
                return true;
            } else {
                return false;
            }
        }).collect(Collectors.toList());

        return ResponseUtil.okList(couponList);
    }

    /**
     * listuser
     *
     * @param userId   用户id
     * @param couponId 优惠券id
     * @param status   状态
     * @param id       id
     * @param addTime  添加时间
     * @param usedTime 使用时间
     * @param page     页面
     * @param limit    限制
     * @param sort     排序
     * @param order    订单
     * @return {@link Object}
     */
    @GetMapping("/listuser")
    @LogAnno
    public Object listuser(Integer userId, Integer couponId, Short status,
                           Integer id, String addTime, String usedTime,
                           @RequestParam(defaultValue = "1") Integer page,
                           @RequestParam(defaultValue = "10") Integer limit,
                           @Sort @RequestParam(defaultValue = "add_time") String sort,
                           @Order @RequestParam(defaultValue = "desc") String order) {
        List<LitemallCouponUser> couponList = couponUserService.queryList(userId, couponId, status, null,
                null, sort, order);
        LocalDate addDate = null;

        LocalDate usedDate = null;

        if (addTime != null) {
            addDate = LocalDate.parse(addTime);
        }

        if (usedTime != null) {
            usedDate = LocalDate.parse(usedTime);
        }

        LocalDate finalAddDate = addDate;
        LocalDate finalUsedDate = usedDate;


        //过滤领取时间和使用时间
        couponList = couponList.stream().filter(couponUser -> {
            boolean addFlag = true;
            boolean usedFlag = true;
            if (finalAddDate != null) {
                if (couponUser.getAddTime().toLocalDate().compareTo(finalAddDate) == 0) {
                    addFlag = true;
                } else {
                    addFlag = false;
                }
            }

            if (finalUsedDate != null) {
                if (couponUser.getUsedTime() != null) {
                    if (couponUser.getUsedTime().toLocalDate().compareTo(finalUsedDate) == 0) {
                        usedFlag = true;
                    } else {
                        usedFlag = false;
                    }
                } else {
                    usedFlag = false;
                }
            }

            //订单编号
            if (couponUser.getOrderId() != null) {
                LitemallOrder o = orderService.findById(couponUser.getOrderId());
                couponUser.setOrderSn(o.getOrderSn());
            }

            if (addFlag && usedFlag) {
                return true;
            } else {
                return false;
            }
        }).collect(Collectors.toList());

        //过滤优惠券码
        if (id != null) {
            couponList = couponList.stream().filter((couponUser -> {
                String couponUserId = couponUser.getId().toString();

                if (couponUserId.indexOf(id.toString()) != -1) {
                    return true;
                } else {
                    return false;
                }
            })).collect(Collectors.toList());
        }
        Pageable pageable = new PageRequest(page - 1, limit);
        PageImpl<LitemallCouponUser> list = PageUtil.getPageLumierePayMemberUserLogVo(pageable, couponList);

        return ResponseUtil.ok(list);
    }

    /**
     * 验证
     *
     * @param coupon 优惠券
     * @return {@link Object}
     */
    private Object validate(LitemallCoupon coupon) {
        String name = coupon.getName();
        if (StringUtils.isEmpty(name)) {
            return ResponseUtil.badArgument();
        }
        return null;
    }

    /**
     * 创建
     *
     * @param coupon 优惠券
     * @return {@link Object}
     */
    @PostMapping("/create")
    @LogAnno
    public Object create(@RequestBody LitemallCoupon coupon) {
        Object error = validate(coupon);
        if (error != null) {
            return error;
        }
        if(coupon.getDays()!=null){
            coupon.setStartTime(null);
            coupon.setEndTime(null);
            coupon.setTimeType((short) 0);
        }else {
            coupon.setDays(null);
            coupon.setTimeType((short) 1);
        }

        // 如果是兑换码类型，则这里需要生存一个兑换码
        if (coupon.getType().equals(org.linlinjava.litemall.db.beans.Constants.TYPE_CODE) || coupon.getType().equals(org.linlinjava.litemall.db.beans.Constants.TYPE_REGISTER)) {
            String code = couponService.generateCode();
            coupon.setCode(code);
            coupon.setDistributeStatus((short) 0);
        }
        // 如果是实物优惠券，则这里需要生存一个二维码
        if (coupon.getType().equals(org.linlinjava.litemall.db.beans.Constants.TYPE_BARCODE)) {
            String code = couponService.generateCouponCode();
            coupon.setBarCode(code);
        }

        //优惠券只有有效天数
        if (coupon.getDays() != null && coupon.getDays() != 0 && coupon.getTimeType().equals((short) 0)) {
            coupon.setStartTime(null);
            coupon.setEndTime(null);
        }


        couponService.add(coupon);
        return ResponseUtil.ok(coupon);
    }

    /**
     * 读
     *
     * @param id      id
     * @param adminId 管理员id
     * @return {@link Object}
     */
    @GetMapping("/read")
    @LogAnno
    public Object read(@NotNull @RequestParam(value = "id") Integer id, @LoginAdminId Integer adminId) {
        LitemallCoupon coupon = couponService.findById(id);
        AdminCouponReadVO adminCouponReadVO = AdminCouponReadVO.builder()
                .receiveNum(couponUserService.countCoupon(coupon.getId()))
                .build();
        BeanUtils.copyProperties(coupon,adminCouponReadVO);
        return ResponseUtil.ok(adminCouponReadVO);
    }

    /**
     * 更新
     *
     * @param coupon 优惠券
     * @return {@link Object}
     */
    @PostMapping("/update")
    @LogAnno
    public Object update(@RequestBody LitemallCoupon coupon) {
        Object error = validate(coupon);
        if (error != null) {
            return error;
        }
        if(coupon.getDays()!=null){
            coupon.setStartTime(null);
            coupon.setEndTime(null);
            coupon.setTimeType((short) 0);
        }else {
            coupon.setDays(null);
            coupon.setTimeType((short) 1);
        }
        if (couponService.update(coupon) == 0) {
            return ResponseUtil.updatedDataFailed();
        }

        if (coupon.getDays() != null && coupon.getDays() != 0) {
            coupon.setStartTime(LocalDateTime.now());
            coupon.setEndTime(LocalDateTime.now().plusDays(coupon.getDays()));
        }
        return ResponseUtil.ok(coupon);
    }

    /**
     * 改变优惠券状态
     *
     * @param id id
     * @return {@link Object}
     */
    @PostMapping("/changeCouponStatus")
    @LogAnno
    public Object changeCouponStatus(@NotNull @RequestParam(value = "id") Integer id) {
        LitemallCoupon coupon = new LitemallCoupon();
        coupon.setId(id);
        int status = 0;
        LitemallCoupon c = couponService.findById(id);
        if (c != null) {
            if (c.getStatus() == 0) {
                //上架之前判断是否已经过期
                if (c.getEndTime() != null && LocalDateTime.now().isAfter(c.getEndTime())) {
                    return ResponseUtil.fail(111, "优惠券已过期，不允许上架");
                }

                status = 1;
            } else if (c.getStatus() == 1) {
                status = 2;
            } else if (c.getStatus() == 2) {
                //上架之前判断是否已经过期
                if (c.getEndTime() != null && LocalDateTime.now().isAfter(c.getEndTime())) {
                    return ResponseUtil.fail(111, "优惠券已过期，不允许上架");
                }

                status = 1;
            }
        }
        coupon.setStatus((short) status);
        coupon.setName(c.getName());
        couponService.updateById(coupon);
        return ResponseUtil.ok();
    }


    /**
     * 删除
     *
     * @param coupon 优惠券
     * @return {@link Object}
     */
    @PostMapping("/delete")
    @LogAnno
    public Object delete(@RequestBody LitemallCoupon coupon) {
        couponService.deleteById(coupon.getId());
        return ResponseUtil.ok();
    }

    /**
     * 商品列表
     * 根据优惠券ID 查询指定商品列表
     *
     * @param id    id
     * @param page  页面
     * @param limit 限制
     * @param sort  排序
     * @param order 订单
     * @return {@link Object}
     */
    @GetMapping("/goodsList")
    @LogAnno
    public Object goodsList(@NotNull @RequestParam(value = "id") Integer id,
                            @RequestParam(defaultValue = "1") Integer page,
                            @RequestParam(defaultValue = "10") Integer limit,
                            @Sort @RequestParam(defaultValue = "add_time") String sort,
                            @Order @RequestParam(defaultValue = "desc") String order) {
        LitemallCoupon coupon = couponService.findById(id);
        //2:指定商品
        if (coupon != null && coupon.getGoodsType() == Constants.GOODS_TYPE_TWO
                && coupon.getGoodsValue() != null && coupon.getGoodsValue().length > 0) {
            IPage<LitemallGoods> litemallGoods = goodsService.querySelective(coupon.getGoodsValue(), page, limit, sort, order);
            return ResponseUtil.okPage(litemallGoods);
        }
        return ResponseUtil.okPage(null);
    }


    /**
     * 区域列表
     * 根据优惠券ID 查询指定商品列表
     *
     * @param id    id
     * @param page  页面
     * @param limit 限制
     * @param sort  排序
     * @param order 订单
     * @return {@link Object}
     */
    @GetMapping("/regionList")
    @LogAnno
    public Object regionList(@NotNull @RequestParam(value = "id") Integer id,
                             @RequestParam(defaultValue = "1") Integer page,
                             @RequestParam(defaultValue = "10") Integer limit,
                             @Sort @RequestParam(defaultValue = "add_time") String sort,
                             @Order @RequestParam(defaultValue = "desc") String order) {
        LitemallCoupon coupon = couponService.findById(id);
        //指定地区
        if (coupon.getRegions() != null) {

            List<LitemallRegion> regions = regionService.findByIds(Arrays.asList(coupon.getRegions()));
            return ResponseUtil.okList(regions == null ? new ArrayList<LitemallRegion>() : regions);
        } else {
            return ResponseUtil.okList(new ArrayList<LitemallRegion>());
        }

    }

    /**
     * 类别列表
     * 根据优惠券ID 查询指定商品类目列表
     *
     * @param id    id
     * @param page  页面
     * @param limit 限制
     * @param sort  排序
     * @param order 订单
     * @return {@link Object}
     */
    @GetMapping("/categoryList")
    @LogAnno
    public Object categoryList(@NotNull @RequestParam(value = "id") Integer id,
                               @RequestParam(defaultValue = "1") Integer page,
                               @RequestParam(defaultValue = "10") Integer limit,
                               @Sort @RequestParam(defaultValue = "add_time") String sort,
                               @Order @RequestParam(defaultValue = "desc") String order) {
        LitemallCoupon coupon = couponService.findById(id);
        //2:指定商品
        List<LitemallCategory> litemallCategories = new ArrayList<>();
        if (coupon != null && coupon.getGoodsType() == Constants.GOODS_TYPE_ONE
                && coupon.getGoodsValue() != null && coupon.getGoodsValue().length > 0) {
            litemallCategories = categoryService.querySelective(Arrays.asList(coupon.getGoodsValue()), page, limit, sort, order);
        }
        return ResponseUtil.okList(litemallCategories);
    }

    /**
     * 使用统计数据
     *
     * @param id        id
     * @param shopId    商店id
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return {@link Object}
     */
    @GetMapping("/statistics")
    @LogAnno
    public Object usedStatistics(@NotNull Integer id, Integer shopId, String startTime, String endTime) {
        Map<String, Object> map = new HashMap<>();
        map.put("pullNumber", couponUserService.countCoupon(id));
        map.put("expiredNumber", couponUserService.countCoupon(id, org.linlinjava.litemall.db.beans.Constants.COUPON_STATUS_EXPIRED));
        LitemallCoupon coupon = couponService.findById(id);
        Integer usedNumber = couponUserService.countCoupon(id, org.linlinjava.litemall.db.beans.Constants.COUPON_STATUS_USED);
        map.put("usedNumber", usedNumber);
        if (null != coupon) {
            map.put("totalDiscount", coupon.getDiscount().multiply(new BigDecimal(usedNumber)));
        }
        List<LitemallOrder> orders = new ArrayList<>();
        List<LitemallCouponUser> litemallCouponUsers = couponUserService.queryByCoupon(id, org.linlinjava.litemall.db.beans.Constants.COUPON_STATUS_USED);
        for (LitemallCouponUser item : litemallCouponUsers) {
            if (null != item.getOrderId()) {
                orders.add(orderService.selectByShop(shopId, item.getOrderId()));
            }
        }
        //订单总价
        BigDecimal orderTotalPrice = new BigDecimal(0.0);
        //订单优惠价
        BigDecimal orderTotalDiscount = new BigDecimal(0.0);
        //订单实际支付价格
        BigDecimal orderTotalActual = new BigDecimal(0.0);
        for (LitemallOrder order : orders) {
            if (order != null) {
                orderTotalPrice = orderTotalPrice.add(order.getOrderPrice());
                orderTotalDiscount = orderTotalDiscount.add(order.getCouponPrice());
                orderTotalActual = orderTotalActual.add(order.getActualPrice());
            }
        }
        map.put("orderTotalPrice", orderTotalPrice);
        map.put("orderTotalDiscount", orderTotalDiscount);
        map.put("orderTotalActual", orderTotalActual);
        return ResponseUtil.ok(map);
    }

    /**
     * 息统计
     * 获取优惠券统计总数据
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param shopId    商店id
     * @return {@link Object}
     */
    @GetMapping("couponStatistic")
    @LogAnno
    public Object couponStatistic(String startTime, String endTime, Integer shopId) {
        CouponQueryDto dto = new CouponQueryDto();
        dto.setType(null);
        dto.setEndTime(endTime);
        dto.setStartTime(startTime);
        dto.setShopId(shopId);
        CouponStatisticVo vo = query(dto);
        return ResponseUtil.ok(vo);
    }

    /**
     * 类型统计
     * 查询每一种优惠券对应的数据
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param shopId    商店id
     * @param page      页面
     * @param limit     限制
     * @return {@link Object}
     */
    @GetMapping("typeStatistic")
    @LogAnno
    public Object typeStatistic(String startTime, String endTime, Integer shopId,Integer page,Integer limit) {
//        CouponQueryDto dto = new CouponQueryDto();
        List<LitemallCoupon> coupons = couponService.queryAllInGener(null,page,limit);
        List<CouponStatisticVo> vos = coupons.stream().map(coupon -> {
            List<LitemallCouponUser> couponUsers = couponUserService.queryList(null, coupon.getId(), null, null, null, null, null);

            //发放量
            Integer total = coupon.getTotal();

//           Map<String,Integer> numMap =  map.get(coupon.getId());

            Integer recieveNum = 0;

            Integer usedNum = 0;

            Integer expiredNum = 0;

//            List<LitemallCouponUser> allUsers = couponUserService.queryList(null, coupon.getId(), null, null, null, null, null);
//            //已领取数量
            Map<Short, List<LitemallCouponUser>> cus = couponUsers.stream().collect(Collectors.groupingBy(LitemallCouponUser::getStatus));

            if (cus.size() != 0) {
                if (cus.get((short) 1) != null) {
                    usedNum = cus.get((short) 1).size();
                }
                if (cus.get((short) 2) != null) {
                    expiredNum = cus.get((short) 2).size();
                }
            }
            recieveNum = couponUsers.size();

//            //使用数量
            //剩余
            Integer surplusNum;
            if (total == 0) {
                surplusNum = 0;
            } else {
                surplusNum = total - recieveNum;
            }


            BigDecimal totalOrderPrice = new BigDecimal(0);
            BigDecimal couponAmountTotal = BigDecimal.ZERO;
            List<LitemallOrder> orderList = orderService.selectJoinList(LitemallOrder.class, new MPJLambdaWrapper<LitemallOrder>()
                    .selectAll(LitemallOrder.class)
                    .leftJoin(LitemallCouponUser.class,LitemallCouponUser::getOrderId,LitemallOrder::getId)
                    .gt(LitemallOrder::getCouponPrice, 0)
                    .eq(shopId!=null,LitemallOrder::getShopId,shopId)
                    .eq(LitemallCouponUser::getCouponId,coupon.getId())
            );
            for (LitemallOrder litemallOrder : orderList) {
                totalOrderPrice=totalOrderPrice.add(litemallOrder.getOrderPrice());
                couponAmountTotal=couponAmountTotal.add(litemallOrder.getCouponPrice());
            }
            CouponStatisticVo vo = new CouponStatisticVo(coupon.getName(), total, recieveNum, surplusNum, usedNum.intValue(), expiredNum.intValue(), totalOrderPrice, couponAmountTotal);
            vo.setCouponId(coupon.getId());
            return vo;
        }).collect(Collectors.toList());


        return ResponseUtil.okList(vos,coupons);
    }

    /**
     * 用户类型统计
     *
     * @param type 类型
     * @return {@link Object}
     */
    @GetMapping("typeUserStatistic")
    @LogAnno
    public Object typeUserStatistic(Integer type) {
        List<LitemallCoupon> coupons = couponService.queryAll(type);

        List<LitemallCouponUser> users = new ArrayList<>();
        coupons.stream().forEach(coupon -> {
            List<LitemallCouponUser> couponUsers = couponUserService.queryList(null, coupon.getId(), null, null, null, null, null);
            users.addAll(couponUsers);
        });

        List<CouponUserVo> userVos = new ArrayList<>();
        userVos = users.stream().map(user -> {
            CouponUserVo userVo = new CouponUserVo();
            BeanUtils.copyProperties(user, userVo);
            LitemallUser u = litemallUserService.findById(user.getUserId());
            userVo.setUserName(u.getUsername());
            userVo.setOrderId(user.getOrderId());
            userVo.setRecieveTime(user.getAddTime());
            return userVo;
        }).collect(Collectors.toList());


        return ResponseUtil.okList(userVos);
    }

    /**
     * 格兰特exten优惠券
     * 管理优惠券发放信息
     *
     * @param dto dto
     * @return {@link Object}
     */
    @PostMapping("grantExtenCoupon")
    @LogAnno
    public Object grantExtenCoupon(@RequestBody(required = false) GrantExtenDto dto) {
        Integer userId = dto.getUserId();
        String remarks = dto.getRemarks();
        remarks = remarks == null ? "" : remarks;
        Integer numbers = dto.getNumbers();
        Integer isAll = dto.getIsAll();
        Integer couponId = dto.getCouponId();
        List<Integer> moneyMemberType = dto.getMoneyMemberType();
        List<Byte> levelMemberType = dto.getLevelMemberType();
        LitemallCoupon coupon = couponService.findById(couponId);
        LocalDateTime startTime;
        LocalDateTime endTime;
        if (coupon.getStartTime() == null && coupon.getEndTime() == null) {
            startTime = LocalDateTime.now();
            endTime = LocalDateTime.now().plusDays(coupon.getDays().intValue());
        } else {
            startTime = coupon.getStartTime();
            endTime = coupon.getEndTime();
        }

        //上架之前判断是否已经过期
        if (coupon.getEndTime() != null && LocalDateTime.now().isAfter(coupon.getEndTime())) {
            return ResponseUtil.fail(111, "优惠券已过期，不允许发送");
        }

        //查询优惠券对应的用户数量
        Integer num = couponUserService.countCoupon(couponId);

        //所有人
        if (isAll == 0) {
//            List<LitemallCouponUser> list = new ArrayList<>();


            List<LitemallUser> users = litemallUserService.queryAllNoInner();

            //判断是否可以发送给每个人指定数量
            if (num + users.size() * numbers > coupon.getTotal()) {
                return ResponseUtil.fail(555, "优惠券发放会导致用户领取数量大于限制数量");
            }

            for (int i = 0; i < users.size(); i++) {


                for (int j = 0; j < numbers; j++) {
                    if (num + 1 > coupon.getTotal()) {
                        break;
                    }
                    LitemallCouponUser couponUser = new LitemallCouponUser();
                    couponUser.setAddTime(LocalDateTime.now());
                    couponUser.setUpdateTime(LocalDateTime.now());
                    couponUser.setStatus((short) 0);
                    couponUser.setDeleted(false);
                    couponUser.setUserId(users.get(i).getId());
                    couponUser.setCouponId(couponId);
                    couponUser.setStartTime(startTime);
                    couponUser.setEndTime(endTime);
//                        list.add(couponUser);
                    litemallCouponUserService.add(couponUser);
                    num++;
                }

                if (users.get(i).getMobile() != null) {
                    awsNotifyService.sendSms(MOBILE_CODE_ONE + users.get(i).getMobile(), remarks, org.linlinjava.litemall.db.beans.Constants.AWS_MESSAGE_TYPE_TRANSACTIONAL);
                }

                if (users.get(i).getEmail() != null) {
                    notifyService.notifyMail("Gift coupon", remarks, users.get(i).getEmail());
                }
                //发送APP消息
                noticeHelper.noticeUser(Constants.MESSAGE_TYPE_SYSTEM, "Coupon gift", remarks, users.get(i).getId(), null);

            }
        } else if (isAll == 1) {
            //指定会员
            Integer existNum = litemallCouponUserService.countUserAndCoupon(userId, couponId);


            //判断是否可以发送给每个人指定数量
            if (num + numbers > coupon.getTotal()) {
                return ResponseUtil.fail(555, "优惠券发放会导致用户领取数量大于限制数量");
            }

            for (int i = 0; i < numbers; i++) {
                LitemallCouponUser cUser = new LitemallCouponUser();
                cUser.setAddTime(LocalDateTime.now());
                cUser.setUpdateTime(LocalDateTime.now());
                cUser.setStatus((short) 0);
                cUser.setDeleted(false);
                cUser.setUserId(userId);
                cUser.setCouponId(couponId);
                cUser.setStartTime(startTime);
                cUser.setEndTime(endTime);
                litemallCouponUserService.add(cUser);
                num++;
            }
            //判断contact是手机还是邮箱
            LitemallUser litemallUser = litemallUserService.findById(userId);
            if (litemallUser !=null && (litemallUser.getMobile() != null || litemallUser.getMobile() != "")) {
//                    notifyService.notifySms(1+litemallUser.getMobile(), remarks);
//                    notifyService.notifySmsTemplate(1+litemallUser.getMobile(), NotifyType.CAPTCHA, new String[]{});
                awsNotifyService.sendSms(MOBILE_CODE_ONE + litemallUser.getMobile(), remarks, org.linlinjava.litemall.db.beans.Constants.AWS_MESSAGE_TYPE_TRANSACTIONAL);
            }

            if (litemallUser.getEmail() != null || litemallUser.getEmail() != "") {
                notifyService.notifyMail("Gift coupon", remarks, litemallUser.getEmail());
            }
            //发送APP消息
            noticeHelper.noticeUser(Constants.MESSAGE_TYPE_SYSTEM, "Coupon gift", remarks, litemallUser.getId(), null);

        } else if (isAll == 2) {

            List<LitemallUser> users = litemallUserService.queryByUserLevels(levelMemberType);

            //判断是否可以发送给每个人指定数量
            if (num + users.size() * numbers > coupon.getTotal()) {
                return ResponseUtil.fail(555, "优惠券发放会导致用户领取数量大于限制数量");
            }

            for (int i = 0; i < users.size(); i++) {

                for (int j = 0; j < numbers; j++) {
                    LitemallCouponUser cUser = new LitemallCouponUser();
                    cUser.setAddTime(LocalDateTime.now());
                    cUser.setUpdateTime(LocalDateTime.now());
                    cUser.setStatus((short) 0);
                    cUser.setDeleted(false);
                    cUser.setUserId(users.get(i).getId());
                    cUser.setCouponId(couponId);
                    cUser.setStartTime(startTime);
                    cUser.setEndTime(endTime);
                    litemallCouponUserService.add(cUser);
                    num++;
                }
                //判断contact是手机还是邮箱
                LitemallUser litemallUser = litemallUserService.findById(users.get(i).getId());
                if (litemallUser.getMobile() != null || litemallUser.getMobile() != "") {
                    awsNotifyService.sendSms(MOBILE_CODE_ONE + litemallUser.getMobile(), remarks, org.linlinjava.litemall.db.beans.Constants.AWS_MESSAGE_TYPE_TRANSACTIONAL);
                }

                if (litemallUser.getEmail() != null || litemallUser.getEmail() != "") {
                    notifyService.notifyMail("Gift coupon", remarks, litemallUser.getEmail());
                }

                //发送APP消息
                noticeHelper.noticeUser(Constants.MESSAGE_TYPE_SYSTEM, remarks, litemallUser.getId(), null);
            }
        } else if (isAll == 3) {
            //查询付费会员对应的用户
            Map<Integer, List<LumierePayMemberUser>> payMemberUserMap = lumierePayMemberUserService.listMemberUserByMemberId(moneyMemberType).
                    stream().collect(Collectors.groupingBy(LumierePayMemberUser::getUserId));

            //判断是否可以发送给每个人指定数量
            if (num + payMemberUserMap.size() * numbers > coupon.getTotal()) {
                return ResponseUtil.fail(555, "优惠券发放会导致用户领取数量大于限制数量");
            }

            for (Integer uId : payMemberUserMap.keySet()) {
                LitemallUser u = litemallUserService.findById(uId);
                if (u != null) {
                    for (int i = 0; i < numbers; i++) {
                        LitemallCouponUser cUser = new LitemallCouponUser();
                        cUser.setAddTime(LocalDateTime.now());
                        cUser.setUpdateTime(LocalDateTime.now());
                        cUser.setStatus((short) 0);
                        cUser.setDeleted(false);
                        cUser.setUserId(u.getId());
                        cUser.setCouponId(couponId);
                        cUser.setStartTime(startTime);
                        cUser.setEndTime(endTime);
                        litemallCouponUserService.add(cUser);
                        num++;
                    }
                    //判断contact是手机还是邮箱
                    LitemallUser litemallUser = litemallUserService.findById(u.getId());
                    if (litemallUser.getMobile() != null || litemallUser.getMobile() != "") {
                        awsNotifyService.sendSms(MOBILE_CODE_ONE + litemallUser.getMobile(), remarks, org.linlinjava.litemall.db.beans.Constants.AWS_MESSAGE_TYPE_TRANSACTIONAL);
                    }

                    if (litemallUser.getEmail() != null || litemallUser.getEmail() != "") {
//                        notifyService.notifyMail(null, remarks, litemallUser.getEmail());
//                        notifyService.notifyMailTemplate("Gift coupon", NotifyType.CAPTCHA, username, new String[]{code});
                        notifyService.notifyMail("Gift coupon", remarks, litemallUser.getEmail());
                    }

                    //发送APP消息
                    noticeHelper.noticeUser(Constants.MESSAGE_TYPE_SYSTEM, remarks, litemallUser.getId(), null);
                }
            }
        }
        //改变优惠券状态
        if (num == coupon.getTotal()) {
            coupon.setDistributeStatus((short) 2);
        } else {
            coupon.setDistributeStatus((short) 1);
        }
        couponService.updateById(coupon);
        return ResponseUtil.ok();

    }

    /**
     * 查询订单优惠券
     *
     * @param couponId 优惠券id
     * @return {@link Object}
     */
    @GetMapping("queryOrderInCoupon")
    @LogAnno
    public Object queryOrderInCoupon(Integer couponId) {
        List<LitemallCouponUser> users = litemallCouponUserService.queryByCoupon(couponId, null);

        List<LitemallOrderDto> orders = users.stream().map(user -> {
            LitemallOrder litemallOrder = litemallOrderService.findById(user.getOrderId());
            LitemallOrderDto orderDto = new LitemallOrderDto();
            if (litemallOrder != null) {
                BeanUtils.copyProperties(litemallOrder, orderDto);

                LitemallShop shop = null;
                if (litemallOrder.getShopId() != null) {
                    shop = shopService.findById(litemallOrder.getShopId());
                }

                if (shop != null) {
                    orderDto.setShopName(shop.getName());
                }

                List<LitemallOrderGoods> goods = orderGoodsService.queryByOid(litemallOrder.getId());

                orderDto.setGoods(goods);

                //根据couponId查询优惠券名称
                LitemallCoupon litemallCoupon = couponService.findById(couponId);
                orderDto.setCouponName(litemallCoupon != null ? litemallCoupon.getName() : null);

//           orderDto.setTransportType(lumiereSubscribe!=null?lumiereSubscribe.getTransportType():null);


                String receiptRange = litemallOrder.getReceiptStartTime() + "--" + litemallOrder.getReceiptEndTime();
                orderDto.setReceiptRange(litemallOrder.getReceiptStartTime() != null || litemallOrder.getReceiptEndTime() != null ? receiptRange : null);

                //查询用户邮箱
                LitemallUser litemallUser = litemallUserService.findById(litemallOrder.getUserId());
                orderDto.setUserName(litemallUser != null ? litemallUser.getUsername() : null);
                return orderDto;
            }
            return null;
        }).collect(Collectors.toList());

        return ResponseUtil.okList(orders);
    }


    /**
     * 查询
     *
     * @param dto dto
     * @return {@link CouponStatisticVo}
     */
    public CouponStatisticVo query(CouponQueryDto dto) {
        //查询优惠券数量
        List<LitemallCoupon> coupons = couponService.queryAll(dto.getType());
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDateTime startTime = null;
        LocalDateTime endTime = null;
        if (dto.getStartTime() != null) {
            startTime = LocalDate.parse(dto.getStartTime(), fmt).atTime(0, 0, 0);
        }

        if (dto.getEndTime() != null) {
            endTime = LocalDate.parse(dto.getEndTime(), fmt).atTime(23, 59, 59);
        }
        List<LitemallCouponUser> couponUsers = litemallCouponUserService.queryAllByDist(startTime, endTime, null);

        //如果type不为空
        Short type = dto == null || dto.getType() == null ? null : dto.getType().shortValue();

        List<Integer> couponIds = couponService.getListByType(type).stream().
                map(LitemallCoupon::getId).distinct().collect(Collectors.toList());
        couponUsers = couponUsers.stream().filter(cUser -> {
            if (couponIds.contains(cUser.getCouponId())) {
                return true;
            } else {
                return false;
            }
        }).collect(Collectors.toList());


        Integer total = 0;
        for (int i = 0; i < coupons.size(); i++) {
            if (coupons.get(i).getTotal() == 0) {
                total = 0;
                break;
            } else {
                total += coupons.get(i).getTotal();
            }
        }

        //已经领取的优惠券
        Integer recieveNum = couponUsers.size();

        //剩余优惠券数量
        Integer surplusNum = total - recieveNum;
        if (total == 0) {
            surplusNum = 0;
        }

        Long usedNum = couponUsers.stream().filter(users -> {
            return users.getStatus() == 1;
        }).count();

        Long expiredNum = couponUsers.stream().filter(users -> {
            return users.getStatus() == 2;
        }).count();

        //优惠券订单总额
        BigDecimal totalOrderPrice = new BigDecimal(0);
        BigDecimal totalCouponPrice = new BigDecimal(0);

        List<LitemallOrder> orderList = orderService.selectJoinList(LitemallOrder.class, new MPJLambdaWrapper<LitemallOrder>()
                .selectAll(LitemallOrder.class)
                .leftJoin(LitemallCouponUser.class,LitemallCouponUser::getOrderId,LitemallOrder::getId)
                .gt(LitemallOrder::getCouponPrice, 0)
                .eq(dto.getShopId()!=null,LitemallOrder::getShopId,dto.getShopId())
        );
        for (LitemallOrder litemallOrder : orderList) {
            totalOrderPrice=totalOrderPrice.add(litemallOrder.getOrderPrice());
            totalCouponPrice=totalCouponPrice.add(litemallOrder.getCouponPrice());
        }
        CouponStatisticVo vo = new CouponStatisticVo(null, total, recieveNum, surplusNum, usedNum.intValue(), expiredNum.intValue(), totalOrderPrice, totalCouponPrice);
        return vo;
    }


}
